/*
 * @Author: wkh
 * @Date: 2021-11-10 15:28:30
 * @LastEditTime: 2021-11-16 18:18:57
 * @LastEditors: wkh
 * @Description: 
 * @FilePath: /kcp-cpp/include/util.hpp
 * 
 */
#ifndef UTIL_HPP_
#define UTIL_HPP_

#include <functional>
#include <memory>
#include <iostream>
#include <atomic>
#include <mutex>
#include <list>

#include <unistd.h>
#include <sys/time.h>
#include <iostream>

#include <string.h>


#include <mutex>
#include <condition_variable>


class FakeLock
{
public:
    void lock() {}
    void unlock() {}
};

template <typename T, bool ThreadSafe = false>
class List
{
public:
    using Lock       = typename std::conditional<ThreadSafe, std::mutex, FakeLock>::type;
    using AutoLock   = std::unique_lock<List<T,ThreadSafe>>;
    using Container  = std::list<T>;
    using value_type = T;
    
public:
    void lock() { return lock_.lock(); }
    void unlock() { return lock_.unlock(); }
    Container &get() { return list_; }

    std::size_t size()
    {
        std::unique_lock<Lock> lock(lock_);
        return list_.size();
    }
    bool empty()
    {
        std::unique_lock<Lock> lock(lock_);
        return list_.empty();
    }
    template <typename U>
    void push_back(U &&x)
    {
        std::unique_lock<Lock> lock(lock_);
        list_.push_back(std::forward<U>(x));
    }

    template <typename... Args>
    void emplace_back(Args &&...args)
    {
        std::unique_lock<Lock> lock(lock_);
        list_.emplace_back(std::forward<Args>(args)...);
    }

    template <typename Fn>
    void for_each(Fn &&fn)
    {
        std::unique_lock<Lock> lock(lock_);
        for (auto &it : list_)
            fn(it);
    }

private:
    Container list_;
    Lock lock_;
};

template <typename T>
using AutoLock = typename T::AutoLock;

template <typename T>
class FakeAtomic
{
public:
    FakeAtomic(T x) : x_(x) {}

    FakeAtomic() noexcept = default;

    T operator++(int) { return x_++; }

    T operator++() { return ++x_; }

    T operator--(int) { return x_--; }

    T operator--() { return --x_; }

    //T load(std::memory_order m = std::memory_order_acq_rel) { return x_; }
    T load() { 
        //TRACE("");
        //printf("%d", x_);
        //TRACE("");
        return x_; 
    }

    //T exchange(T x, std::memory_order m = std::memory_order_acq_rel)
    T exchange(T x)
    {
        T tmp = x_;
        x_ = x;
        return tmp;
    }

    //bool compare_exchange_weak(T &expected, T desired,
    //                           std::memory_order s = std::memory_order_acq_rel) noexcept
    bool compare_exchange_weak(T &expected, T desired ) noexcept
    {
        if (expected != x_)
        {
            expected = x_;
            return false;
        }

        x_ = desired;
        return true;
    }

    //void store(T x, std::memory_order m = std::memory_order_acq_rel) { x_ = x; }
    void store(T x) { 
        //TRACE("");
        x_ = x; 
    }

private:
    FakeAtomic(const FakeAtomic &) = delete;

    FakeAtomic &operator=(const FakeAtomic &) = delete;

    FakeAtomic &operator=(const FakeAtomic &) volatile = delete;


private:
    T x_;
};

inline uint32_t bound(const uint32_t lower,const uint32_t middle,const uint32_t upper)
{
        return std::min(std::max(lower,middle),upper);
}






/* get system time */
static inline void itimeofday(long *sec, long *usec)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    if (sec) *sec = time.tv_sec;
    if (usec) *usec = time.tv_usec;
}

/* get clock in millisecond 64 */
static inline int64_t iclock64()
{
    long s, u;
    int64_t value;
    itimeofday(&s, &u);
    value = ((int64_t)s) * 1000 + (u / 1000);
    return value;
}
/* get clock in usec */
//static inline int64_t iclock64()
//{
//    long s, u;
//    int64_t value;
//    itimeofday(&s, &u);
//    value = ((int64_t)s) * 1000 + u;
//    return value;
//}



//print the process bar
void procBar(int current, int total)
{
    if(current>total)return ;

    printf("[%d/%d]", current, total); 

    int i = (int)(((double)current/(double)total)*100);

    char buf[102];
    memset(buf, '\0', sizeof(buf));
    const char *lable = "|/-\\";

    for(int j = 0; j <= 100; j++)
    {   
      if(j<=i)
      {   
        if(j==i)
          buf[j]='>';
        else
          buf[j]='=';
      }   
      else
      {   
        buf[j]=':';                                                                                                                            
      }   
    }   
#ifndef DEBUG_
    printf("[%-101s][%d%%]", buf, i); 
    if(current<total)
    {   
      printf("[%c]\r", lable[iclock64()%4]);
      fflush(stdout);
    }
    else if(current>=total)
    {
      printf("[%c]\n",'@');
      fflush(stdout);
    }
#else
    printf("[%-101s][%d%%][%c]\n", buf, i, lable[iclock64()%4]);
#endif
}


// uint8_t ->string

#include <stdint.h>
#include <sstream>
#include <string.h>
#include <string>
#include <algorithm>

// 将uint8_t转换为16进制的std::string
std::string encodeToHexStr(uint8_t uint8Var, bool upperCase) {
    int intVar = (int)uint8Var;
    std::stringstream ss;
    ss << std::hex << intVar;
    std::string hexStrVar = ss.str();
    if (upperCase) {
        std::transform(hexStrVar.begin(), hexStrVar.end(), hexStrVar.begin(), ::toupper);
    } else {
        std::transform(hexStrVar.begin(), hexStrVar.end(), hexStrVar.begin(), ::tolower);
    }
    return hexStrVar;
}

// 将16进制的std::string转换为uint8_t
bool decodeFromHexStr(std::string hexStr, uint8_t& ucValue) {
    const char* bufStr = hexStr.c_str();
    ucValue = 0;

    char buf[3], tmpChar;
    memset((void*)buf, 0, 3);
    size_t sizeStr = strlen(bufStr);
    if (sizeStr < 1) {
        return false;
    }

    if (sizeStr == 1) {
        buf[0] = '0';
        buf[1] = bufStr[0];
    } else {
        memcpy((void*)buf, (void*)bufStr, 2);
    }

    for (int i = 0; i < 2; i++) {
        tmpChar = buf[i];
        ucValue = ucValue * 16;
        if (tmpChar >= '0' && tmpChar <= '9') {
            ucValue = ucValue + (uint8_t)(tmpChar - '0');
        } else if (tmpChar >= 'a' && tmpChar <= 'f') {
            ucValue = ucValue + (uint8_t)(tmpChar - 'a' + 10);
        } else if (tmpChar >= 'A' && tmpChar <= 'F') {
            ucValue = ucValue + (uint8_t)(tmpChar - 'A' + 10);
        } else {
            return false;
        }
    }
    return true;
}

//IOQueue
#include <assert.h>
class H_Uint8
{
public:
    uint8_t* data=NULL;
    int size=0;
public:
    //int ioType;
    //unsigned int requestIndex;
    H_Uint8(int size){
      data = new uint8_t[size+1];
      memset(data, 0, size);
    }
    H_Uint8(uint8_t* array, int size){
      data = new uint8_t[size];
      memcpy(data, array, size);
    }
    void free()
    {
      if(data!=NULL)
      {
        delete [] data;
        data = NULL;
      }
    }
    ~H_Uint8()
    {
    }
};

struct QueueMember
{
    QueueMember* p;
    //int data;
    uint8_t* data;
    int size;
    //int ioType;
    //unsigned int requestIndex;
    QueueMember(uint8_t* array, int size){
      data = new uint8_t[size];
      memcpy(data, array, size);
    }
    ~QueueMember()
    {
      delete [] data;
    }
};

class HQueue
{
public:
    HQueue()
        : pHead(nullptr),
          pTail(nullptr),
          count(0)
    {
    }

    // 队列是否为空
    bool empty() 
    {
        //std::lock_guard<std::mutex> lk(mut);
        return (pHead == nullptr);
    }

    // 返回队列中元素个数
    size_t size()
    {
        //std::lock_guard<std::mutex> lk(mut);
        return count;
    }

    // 返回队头元素
    QueueMember* front()
    {
        //std::lock_guard<std::mutex> lk(mut);
        assert(!empty());
        return pHead;
    }

    // 返回队尾元素
    QueueMember* back()
    {
        //std::lock_guard<std::mutex> lk(mut);
        assert(!empty());
        return pTail;
    }

    // 将变量request从队列尾入队
    void push(uint8_t* uint8_varray, int size)
    {   
        //std::lock_guard<std::mutex> lk(mut);
        //std::unique_lock<std::mutex> lk(mut);
        
        QueueMember* aQueueMember = new QueueMember(uint8_varray, size); 
        aQueueMember->p = nullptr;
        if (pHead == nullptr)
        {
            assert(pTail == nullptr);
            pHead = aQueueMember;
        }
        else
        {
            assert(pTail != nullptr);
            pTail->p = aQueueMember;
        }
        pTail = aQueueMember;
        count++;

        //cond.notify_one();
    }

    // 将队头元素弹出
    void pop()
    {
        //std::unique_lock<std::mutex> lk(mut);
        //cond.wait(lk, [this](){return !this->empty();});

        assert(!empty());
        QueueMember* pHead_tmp = pHead;
        pHead = pHead->p;
        delete pHead_tmp;
        if (pHead == nullptr)
        {
            pTail = nullptr;
        }
        count--;
    }

private:
    QueueMember* pHead;
    QueueMember* pTail;
    size_t count;

    std::mutex mut;
    std::condition_variable cond;
};





#endif
